package com.yx.serialport;



import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * 串口通信类
 * 提供打开、关闭串口以及获取输入输出流的功能
 */

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class SerialPort {
    /**
     * 获取所有可能的串口设备路径
     * @return 串口设备路径列表
     */
    public static List<String> getPossibleSerialPorts() {
        List<String> devices = new ArrayList<>();

        // 常见的串口设备路径
        String[] possiblePaths = {
                "/dev/ttyS",      // 标准串口
                "/dev/ttyUSB",    // USB转串口
                "/dev/ttyACM",    // ACM设备 (如Arduino)
                "/dev/ttyO",      // 一些嵌入式设备的串口
                "/dev/ttyAMA",    // AMBA串口 (如树莓派)
                "/dev/ttyMT",     // MTK平台串口
                "/dev/ttyHSL",    // 高通平台串口
                "/dev/ttyHS",     // 高速串口
                "/dev/serial",    // 某些设备的串口目录
                "/dev/bus/usb"    // USB总线设备
        };

        // 检查常见的串口设备
        for (String basePath : possiblePaths) {
            for (int i = 0; i < 10; i++) { // 检查0-9号设备
                String devicePath = basePath + i;
                File device = new File(devicePath);
                if (device.exists()) {
                    devices.add(devicePath);
                }
            }
        }

        // 检查/dev目录下的所有tty设备
        File devDir = new File("/dev");
        File[] files = devDir.listFiles();
        if (files != null) {
            for (File file : files) {
                String fileName = file.getName();
                if (fileName.startsWith("tty") && !fileName.contains("tty")) {
                    // 排除虚拟终端设备
                    if (!fileName.startsWith("tty") ||
                            fileName.startsWith("ttyS") ||
                            fileName.startsWith("ttyUSB") ||
                            fileName.startsWith("ttyACM") ||
                            fileName.startsWith("ttyO") ||
                            fileName.startsWith("ttyAMA") ||
                            fileName.startsWith("ttyMT") ||
                            fileName.startsWith("ttyHSL") ||
                            fileName.startsWith("ttyHS")) {
                        devices.add("/dev/" + fileName);
                    }
                }
            }
        }

        return devices;
    }

    /**
     * 获取可用的串口设备（有读写权限的）
     * @return 可用串口设备列表
     */
    public static List<String> getAvailableSerialPorts() {
        List<String> allPorts = getPossibleSerialPorts();
        List<String> availablePorts = new ArrayList<>();

        for (String port : allPorts) {
            File device = new File(port);
            if (device.canRead() && device.canWrite()) {
                availablePorts.add(port);
            }
        }

        return availablePorts;
    }

    /**
     * 尝试获取串口设备的读写权限
     * @param devicePath 设备路径
     * @return 是否成功获取权限
     */
    public static boolean acquireSerialPortPermission(String devicePath) {
        try {
            Process su = Runtime.getRuntime().exec("su");
            String cmd = "chmod 666 " + devicePath + "\n" + "exit\n";
            su.getOutputStream().write(cmd.getBytes());
            int result = su.waitFor();
            return result == 0;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    private static final String TAG = "SerialPort";

    // 数据位常量
    public static final int DATABITS_5 = 5;
    public static final int DATABITS_6 = 6;
    public static final int DATABITS_7 = 7;
    public static final int DATABITS_8 = 8;

    // 停止位常量
    public static final int STOPBITS_1 = 1;
    public static final int STOPBITS_2 = 2;

    // 校验位常量
    public static final int PARITY_NONE = 0;
    public static final int PARITY_ODD = 1;
    public static final int PARITY_EVEN = 2;

    static {
        System.loadLibrary("serial_port");
    }

    private FileDescriptor mFd;
    private FileInputStream mFileInputStream;
    private FileOutputStream mFileOutputStream;

    public SerialPort(File device, int baudrate, int dataBits, int stopBits,
                      int parity, int flags) throws SecurityException, IOException {
        // 检查设备权限
        if (!device.canRead() || !device.canWrite()) {
            try {
                Process su = Runtime.getRuntime().exec("/system/bin/su");
                String cmd = "chmod 666 " + device.getAbsolutePath() + "\n" + "exit\n";
                su.getOutputStream().write(cmd.getBytes());

                if ((su.waitFor() != 0) || !device.canRead() || !device.canWrite()) {
                    throw new SecurityException("无法获取串口读写权限");
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw new SecurityException("无法获取串口读写权限: " + e.getMessage());
            }
        }

        mFd = open(device.getAbsolutePath(), baudrate, dataBits, stopBits, parity, flags);
        if (mFd == null) {
            throw new IOException("无法打开串口: " + device.getAbsolutePath());
        }

        mFileInputStream = new FileInputStream(mFd);
        mFileOutputStream = new FileOutputStream(mFd);
    }

    public InputStream getInputStream() {
        return mFileInputStream;
    }

    public OutputStream getOutputStream() {
        return mFileOutputStream;
    }

    public void close1() {
        try {
            if (mFileInputStream != null) {
                mFileInputStream.close();
                mFileInputStream = null;
            }
            if (mFileOutputStream != null) {
                mFileOutputStream.close();
                mFileOutputStream = null;
            }
            if (mFd != null) {
                close();  // 调用本地方法
                mFd = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public boolean isOpen() {
        return mFd != null;
    }

    // JNI 方法声明 - 注意方法名与 C/C++ 代码匹配
    private native static FileDescriptor open(String path, int baudrate, int dataBits,
                                              int stopBits, int parity, int flags);
    private native  void close();  // 方法名应该是 close 而不是 closeNative

    // 其他辅助方法...
    public static int[] getSupportedBaudrates() {
        return new int[] {
                0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
                9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000,
                921600, 1000000, 1152000, 1500000, 2000000, 2500000, 3000000,
                3500000, 4000000
        };
    }

    public static int[] getSupportedDataBits() {
        return new int[] {5, 6, 7, 8};
    }

    public static int[] getSupportedStopBits() {
        return new int[] {1, 2};
    }

    public static int[] getSupportedParity() {
        return new int[] {PARITY_NONE, PARITY_ODD, PARITY_EVEN};
    }

    public static String getParityName(int parity) {
        switch (parity) {
            case PARITY_NONE: return "NONE";
            case PARITY_ODD: return "ODD";
            case PARITY_EVEN: return "EVEN";
            default: return "UNKNOWN";
        }
    }

    @Override
    protected void finalize() throws Throwable {
        try {
            // 添加空值检查
            if (mFd != null) {
                close();
            }

        } finally {
            super.finalize();
        }
    }
}